package com.bestcem.xm.award.service.impl;

import com.bestcem.xm.award.constant.RedisKeyConstant;
import com.bestcem.xm.award.controller.param.point.BandPointSaveAllParam;
import com.bestcem.xm.award.controller.vo.point.BandPointDeleteCheckVO;
import com.bestcem.xm.award.dao.AwardAwardDao;
import com.bestcem.xm.award.dao.BandPointDao;
import com.bestcem.xm.award.entity.pojo.BandPointDO;
import com.bestcem.xm.award.enums.RecordFlagStatusEnum;
import com.bestcem.xm.award.service.BandPointService;
import com.bestcem.xm.award.service.bo.point.BandPointListBO;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.StringUtil;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 品牌积分service
 *
 * @author xa.zhang <xa.zhang@idiaoyan.com>
 * @version v1.0
 * @date 2021/7/8 13:49
 */
@Slf4j
@Service
public class BandPointServiceImpl implements BandPointService {

    /**
     * 同一个租户下的品牌积分总数最大值
     */
    public static final int MAX_COUNT = 50;
    @Resource
    private BandPointDao bandPointDao;
    @Resource
    private AwardAwardDao awardDao;
    @Resource
    private RedisService redisService;

    /**
     * 删除后，不能再建被删除的那个code
     * 租户下积分名称不可重复
     * 品牌积分奖励中创建的积分类型（如金豆），对其进行删除时遵循以下规则：
     * 1、删除积分类型（如金豆）时，如果存在“已结束”状态的或者已删除的奖励使用了该积分类型，那么可以正常删除，否则不行，提示“存在未结束的奖励使用该积分“
     * 2、删除积分后，不影响使用该积分的奖励（能正常显示），不影响中奖明细中该积分的显示
     *
     * @param param 参数
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult<String> save(BandPointSaveAllParam param) {
        String orgId = param.getOrgId();
        redisService.lock(String.format(RedisKeyConstant.BAND_POINT_OPERATE, orgId));
        try {
            //校验新增的是否有重复的code name
            ServiceResult preCheck = savePreCheck(param);
            if (!preCheck.isSuccess()) {
                return preCheck;
            }

            //先检查是否可删除
            ServiceResult deleteCheck = checkCanDeleteId(param);
            if (!deleteCheck.isSuccess()) {
                return deleteCheck;
            }

            //保存待删id集合
            List<String> deleteIdList = new ArrayList();
            for (BandPointSaveAllParam.DeleteParam deleteParam : param.getDeleteList()) {
                deleteIdList.add(deleteParam.getId());
            }

            //检查是否可新增，排除掉待删的id
            ServiceResult addCheck = checkCanAdd(param, deleteIdList);
            if (!addCheck.isSuccess()) {
                return addCheck;
            }

            //条数校验
            long count = bandPointDao.countByOrgIdNotDel(orgId);
            long expectCount = count + param.getAddList().size() - param.getDeleteList().size();
            if (expectCount > MAX_COUNT) {
                return ServiceResult.fail("品牌积分总数最多50个");
            }

            if (deleteIdList.size() > 0) {
                bandPointDao.updateDelFlagById(deleteIdList);
            }

            List<BandPointDO> list = new ArrayList<>();
            for (BandPointSaveAllParam.AddParam addParam : param.getAddList()) {
                BandPointDO bandPoint = new BandPointDO();
                bandPoint.setPointId(StringUtil.getId());
                bandPoint.setName(addParam.getName());
                bandPoint.setOrgId(orgId);
                bandPoint.setCode(addParam.getCode());
                bandPoint.setRecordFlag(RecordFlagStatusEnum.ACTIVE.getIndex());

                list.add(bandPoint);
            }
            bandPointDao.insertList(list);

            return ServiceResult.success();
        } finally {
            redisService.unlock(String.format(RedisKeyConstant.BAND_POINT_OPERATE, orgId));
        }
    }

    /**
     * 检查新增的是否有重复的code或者name
     *
     * @param param 参数
     * @return 结果
     */
    private ServiceResult savePreCheck(BandPointSaveAllParam param) {
        List<BandPointSaveAllParam.AddParam> addList = param.getAddList();
        Map<String, String> codeMap = Maps.newHashMap();
        Map<String, String> nameMap = Maps.newHashMap();
        for (BandPointSaveAllParam.AddParam addParam : addList) {
            if (addParam == null) {
                continue;
            }
            if (StringUtils.isNotBlank(addParam.getCode())) {
                if (codeMap.containsKey(addParam.getCode())) {
                    return ServiceResult.fail("新增的有重复的序号");
                }
                codeMap.put(addParam.getCode(), "");
            }

            if (StringUtils.isNotBlank(addParam.getName())) {
                if (nameMap.containsKey(addParam.getName())) {
                    return ServiceResult.fail("新增的有重复的名称");
                }
                nameMap.put(addParam.getName(), "");
            }
        }
        return ServiceResult.success();
    }


    /**
     * 检查是否可添加
     *
     * @param param        参数
     * @param deleteIdList 删除列表
     * @return 结果
     */
    private ServiceResult checkCanAdd(BandPointSaveAllParam param, List<String> deleteIdList) {
        for (BandPointSaveAllParam.AddParam addParam : param.getAddList()) {
            BandPointDO bandPoint = bandPointDao.findByNameNotDel(addParam.getName(), param.getOrgId());
            if (bandPoint != null && (!deleteIdList.contains(bandPoint.getPointId()))) {
                return ServiceResult.fail("品牌积分名称[" + addParam.getName() + "]已存在");
            }

            //code可以为空
            if (StringUtils.isNotBlank(addParam.getCode())) {
                BandPointDO codeCheck = bandPointDao.findByCode(addParam.getCode(), param.getOrgId());
                if (codeCheck != null) {
                    return ServiceResult.fail("品牌序号[" + addParam.getCode() + "]已存在或者跟已删除的相同");
                }
            }
        }
        return ServiceResult.success();
    }


    /**
     * 检查是否可删除
     *
     * @param param 参数
     * @return 结果
     */
    private ServiceResult checkCanDeleteId(BandPointSaveAllParam param) {
        for (BandPointSaveAllParam.DeleteParam deleteParam : param.getDeleteList()) {
            boolean flag = awardDao.existsNotDeleteAwardByPointId(deleteParam.getId());
            if (flag) {
                return ServiceResult.fail("存在未结束的奖励使用该积分，不可删除,积分名称:" + deleteParam.getName());
            }
        }
        return ServiceResult.success();
    }


    /**
     * 查询列表
     *
     * @param curPage     页码
     * @param rowsPerPage 每页数量
     * @param orgId       公司id
     * @return 结果
     */
    @Override
    public ServiceResult<BandPointListBO> findAllByPage(Integer curPage, Integer rowsPerPage, String orgId) {

        long count = bandPointDao.countByOrgIdNotDel(orgId);

        int start = (curPage - 1) * 10;

        List<BandPointDO> list = bandPointDao.findAllByPage(start, rowsPerPage, orgId);

        BandPointListBO bandPointListBO = new BandPointListBO();
        bandPointListBO.setTotal(Long.valueOf(count).intValue());
        List<BandPointListBO.BandPoint> bandPointList = new ArrayList<>();
        bandPointListBO.setRows(bandPointList);
//       mongod获取list源码可以出来，必不为null。但是mongodb假如升级了，需要注意，是否还不为null
        for (BandPointDO bandPoint : list) {
            BandPointListBO.BandPoint bandPointBO = new BandPointListBO.BandPoint();
            bandPointBO.setId(bandPoint.getPointId());
            bandPointBO.setName(bandPoint.getName());
            bandPointBO.setCode(bandPoint.getCode());

            bandPointList.add(bandPointBO);
        }

        return ServiceResult.success(bandPointListBO);
    }

    /**
     * 品牌积分删除前校验
     *
     * @param id  参数：品牌积分id
     * @return 结果
     */
    @Override
    public ServiceResult<BandPointDeleteCheckVO> checkDelete(String id) {

        //检查是否可删除
        boolean flag = awardDao.existsNotDeleteAwardByPointId(id);
        BandPointDeleteCheckVO checkResult=new BandPointDeleteCheckVO();
        checkResult.setCheckResult(!flag);

        return ServiceResult.success(checkResult);
    }

}
